using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Text;
using System.Windows.Forms;

using FinlogiK.FxCop.Statistics.Windows.Data;
using FinlogiK.FxCop.Statistics.Windows.Data.ProjectDataSetTableAdapters;
using FinlogiK.FxCop.Statistics.Windows.Properties;


namespace FinlogiK.FxCop.Statistics.Windows
{
	internal partial class AnalysisForm : Form
	{
		#region Constructors

		internal AnalysisForm()
		{
			this.InitializeComponent();

			this.BindProjectsDropDown();
		}

		#endregion

		#region Properties

		private string StatusText
		{
			get
			{
				return ((MainForm)this.MdiParent).StatusText;
			}
			set
			{
				((MainForm)this.MdiParent).StatusText = value;
			}
		}

		#endregion

		#region Methods

		private void BindProjectsDropDown()
		{
			using (ProjectsTableAdapter adapter = new ProjectsTableAdapter())
			{
				ProjectDataSet.ProjectsDataTable table = new ProjectDataSet.ProjectsDataTable();
				adapter.Fill(table, null);

				this.projectIdComboBox.DataSource = table;
				this.projectIdComboBox.DisplayMember = "ProjectName";
				this.projectIdComboBox.ValueMember = "ProjectId";
			}
		}

		private void startButton_Click(object sender, EventArgs e)
		{
			int? projectId = (int?)this.projectIdComboBox.SelectedValue;
			string projectName = (string)((DataRowView)this.projectIdComboBox.SelectedItem)["ProjectName"];

			if (projectId == null)
			{
				MessageBoxEx.Show(Resources.ValidationNoProject, MessageBoxIcon.Exclamation);
				this.projectIdComboBox.Focus();
			}
			else
			{
				this.Cursor = Cursors.WaitCursor;
				this.startButton.Enabled = false;
				this.cancelButton.Enabled = true;
				this.backgroundWorker.RunWorkerAsync(new AnalysisInput(projectId.Value, projectName));
			}
		}

		private void cancelButton_Click(object sender, EventArgs e)
		{
			this.backgroundWorker.CancelAsync();
			this.StatusText = Resources.StatusCancelling;
		}

		private AnalysisOutput RunAnalysis(AnalysisInput input)
		{
			StatisticsCollector statisticsCollector = new StatisticsCollector(Settings.Default.StatisticsDatabase, input.ProjectName);
			statisticsCollector.AnalysisOperationStarting += new EventHandler<AnalysisOperationStartingEventArgs>(this.OnAnalysisOperationStarting);
			statisticsCollector.AnalysisOperationEnded += new EventHandler<AnalysisOperationEndedEventArgs>(this.OnAnalysisOperationEnded);

			DateTime analysisTimestamp = statisticsCollector.CollectStatistics();
			return new AnalysisOutput(input.ProjectId, analysisTimestamp);
		}

		private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
		{
			e.Result = this.RunAnalysis((AnalysisInput)e.Argument);
			if (this.backgroundWorker.CancellationPending) e.Cancel = true;
		}

		private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
		{
			switch (e.ProgressPercentage)
			{
				case 0:
					AnalysisOperationStartingEventArgs startingEventArgs = (AnalysisOperationStartingEventArgs)e.UserState;
					this.ShowOperationStarted(startingEventArgs.Operation);
					break;
				case 100:
					AnalysisOperationEndedEventArgs endedEventArgs = (AnalysisOperationEndedEventArgs)e.UserState;
					this.ShowOperationEnded(endedEventArgs.Operation, endedEventArgs.Duration);
					break;
			}
		}

		private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
		{
			this.Cursor = Cursors.Default;
			this.startButton.Enabled = true;
			this.cancelButton.Enabled = false;
			this.StatusText = string.Empty;

			if (e.Cancelled)
			{
				MessageBoxEx.Show(Resources.AnalysisRunCancelled, MessageBoxIcon.Warning);
			}
			else if (e.Error != null)
			{
				MessageBoxEx.Show(string.Format(CultureInfo.CurrentCulture, 
					Resources.ExceptionThrownDuringAnalysisRun,
					Environment.NewLine, e.Error.ToString()),
					MessageBoxIcon.Error);
			}
			else
			{
				if (MessageBoxEx.Show(Resources.AnalysisRunCompletedSuccessfully, MessageBoxButtons.YesNo,
					MessageBoxIcon.Question) == DialogResult.Yes)
				{
					AnalysisOutput output = (AnalysisOutput)e.Result;
					((MainForm)this.MdiParent).ShowAnalysisResults(output.ProjectId, output.AnalysisTimestamp);
				}
			}
		}

		private static int GetOperationListIndex(AnalysisOperation startingOperation)
		{
			int operationListIndex;
			switch (startingOperation)
			{
				case AnalysisOperation.TodoExclusionRemoval:
					operationListIndex = 0;
					break;
				case AnalysisOperation.TodoViolationDetection:
					operationListIndex = 1;
					break;
				case AnalysisOperation.TodoViolationStatisticsPersistence:
					operationListIndex = 2;
					break;
				case AnalysisOperation.RuleActivation:
					operationListIndex = 3;
					break;
				case AnalysisOperation.TotalViolationDetection:
					operationListIndex = 4;
					break;
				case AnalysisOperation.TotalViolationStatisticsPersistence:
					operationListIndex = 5;
					break;
				default:
					throw new InvalidEnumArgumentException("startingOperation", (int)startingOperation, typeof(AnalysisOperation));
			}

			return operationListIndex;
		}

		private void OnAnalysisOperationStarting(object sender, AnalysisOperationStartingEventArgs e)
		{
			if (this.backgroundWorker.CancellationPending)
			{
				e.Cancel = true;
			}
			else
			{
				this.backgroundWorker.ReportProgress(0, e);
			}
		}

		private void OnAnalysisOperationEnded(object sender, AnalysisOperationEndedEventArgs e)
		{
			this.backgroundWorker.ReportProgress(100, e);
		}

		private void ShowOperationStarted(AnalysisOperation operation)
		{
			int listIndex = AnalysisForm.GetOperationListIndex(operation);
			ListViewItem.ListViewSubItemCollection subItems = this.operationList.Items[listIndex].SubItems;
			if (subItems.Count == 1) subItems.Add(string.Empty);
			subItems[1].Text = Resources.AnalysisOperationWorking;
		}

		private void ShowOperationEnded(AnalysisOperation operation, TimeSpan duration)
		{
			int listIndex = AnalysisForm.GetOperationListIndex(operation);
			ListViewItem.ListViewSubItemCollection subItems = this.operationList.Items[listIndex].SubItems;
			if (subItems.Count == 1) subItems.Add(string.Empty);
			subItems[1].Text = string.Format(CultureInfo.CurrentCulture,
				Resources.AnalysisOperationCompleted, duration.TotalMinutes);
		}

		#endregion

		#region Nested types

		private sealed class AnalysisInput
		{
			#region Fields

			private readonly int _projectId;
			private readonly string _projectName;

			#endregion

			#region Constructors

			internal AnalysisInput(int projectId, string projectName)
			{
				this._projectId = projectId;
				this._projectName = projectName;
			}

			#endregion

			#region Properties

			internal int ProjectId
			{
				get
				{
					return this._projectId;
				}
			}

			internal string ProjectName
			{
				get
				{
					return this._projectName;
				}
			}

			#endregion
		}

		private sealed class AnalysisOutput
		{
			#region Fields

			private readonly int _projectId;
			private readonly DateTime _analysisTimestamp;

			#endregion

			#region Constructors

			internal AnalysisOutput(int projectId, DateTime analysisTimestamp)
			{
				this._projectId = projectId;
				this._analysisTimestamp = analysisTimestamp;
			}

			#endregion

			#region Properties

			internal int ProjectId
			{
				get
				{
					return this._projectId;
				}
			}

			internal DateTime AnalysisTimestamp
			{
				get
				{
					return this._analysisTimestamp;
				}
			}

			#endregion
		}

		#endregion
	}
}
